home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 45 / Amiga Format CD45 (1999-09)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-11].iso / -serious- / misc / mcread / original / macwrite.c < prev    next >
C/C++ Source or Header  |  1999-08-09  |  8KB  |  309 lines

  1. /*    mcread: macwrite.c
  2.     Copyright (C) 1991, Mike Gleason Jr & NCEMRSoft.
  3.     All Rights Reserved. */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include "mcread.h"
  8.  
  9. typedef struct {
  10.     short    type;            /* 0-1 */
  11.     short    unused1[3];        /* 2-7 */
  12.     long    offset;            /* 8-11 */
  13.     short    len;            /* 12-13 */
  14.     short    unused2;        /* 14-15 */
  15. } MacWrite_Paragraph_Info;
  16.  
  17. #define MACWRITE_45                6
  18. #define MACWRITE_22                3
  19.  
  20. #define DEFAULT_COMMON            " etnroaisdlhcfp"
  21.     /*     Most commonly occurring characters, MacWrite uses a crude
  22.         compression scheme with these.  The default uses the American
  23.         version. */
  24.  
  25. #define COMPRESSED_MASK            0x08
  26.  
  27. char                            CommonChars[20];
  28. int                                GNNeedToReadByte = 1;    /* for Getn() */
  29.  
  30. int thrash_macwrite(in, name, dataforklen)
  31.     FILE *in;
  32.     char *name;
  33.     long dataforklen;
  34. {
  35.     MacWrite_Paragraph_Info        P;
  36.     long                        dataOffset, infoOffset, saved;
  37.     register long                Seek, StartOffset;
  38.     char                        paragraphStatus;
  39.     register int                a, b, c, nibble, parIsCompressed;
  40.     short                        version, numparas, curpara;
  41.     short                        bytesInParagraph, bytesOut;
  42. #define CheckReadErr             if (ferror(in)) goto ReadErr
  43. #define CheckSeekErr             if (Seek) goto SeekErr;
  44.  
  45.     bytesOut = curpara = 0;
  46.     (void) strcpy(CommonChars, (char *)DEFAULT_COMMON);
  47.     
  48.     if (dataforklen >= 0)
  49.         (void) FindCommon(in, dataforklen);
  50.     
  51.     StartOffset = ftell(in);    /*    for macbinary files, this will be 128,
  52.                                     otherwise it should be zero. */
  53.                                     
  54.     version = (short) Getw (in);
  55.     CheckReadErr;
  56.     
  57.     if (version != MACWRITE_45)    {
  58.         if (version == MACWRITE_22)
  59.             (void) fprintf (stderr, "%s: macwrite format too old (2.2)\n", name);
  60.         else if (dataforklen) {
  61.             if (version > MACWRITE_45)
  62.                 (void) fprintf (stderr, "%s: macwrite format too new (%d)\n", name, version);
  63.             else
  64.                 (void) fprintf (stderr, "%s: macwrite format too old (%d)\n", name, version);
  65.         }
  66.         return (3);
  67.     }
  68.     
  69.     numparas = (short) Getw (in);
  70.     CheckReadErr;
  71.     
  72.     Seek = fseek (in, (long) (StartOffset + 264), SEEK_SET);
  73.     CheckSeekErr;
  74.         /* should now point to the variables for the body text. */
  75.         
  76.     infoOffset = (long) Getl (in);
  77.     CheckReadErr;
  78.     
  79.     Seek = fseek (in, (StartOffset + infoOffset), SEEK_SET);
  80.     CheckSeekErr;
  81.     
  82.     /* loop through and read all the paragraphs */
  83.     
  84.     while (1) {
  85.         P.type = (short) Getw (in);         if (ferror(in)) break;
  86.         P.unused1[0] = (short) Getw (in);   if (ferror(in)) break;
  87.         P.unused1[1] = (short) Getw (in);   if (ferror(in)) break;
  88.         P.unused1[2] = (short) Getw (in);   if (ferror(in)) break;
  89.         P.offset = (long) Getl (in);        if (ferror(in)) break;
  90.         P.len = (short) Getw (in);          if (ferror(in)) break;
  91.         P.unused2 = (short) Getw (in);      if (ferror(in)) break;
  92.         
  93.         dataOffset = P.offset & 0x00ffffff;        /* lo 3 bytes only */
  94.         paragraphStatus = (char) (P.offset >> 24);        
  95.         
  96.         if (P.type < 0) {                        /* a PICT paragraph */
  97.             (void) puts ("### picture omitted!");
  98.             if (CheckPage())
  99.                 return (0);
  100.         }
  101.         if (P.type > 0)    {                        /* a text paragraph */
  102.             saved = ftell (in);
  103.             Seek = fseek (in, (StartOffset + dataOffset), SEEK_SET);
  104.             CheckSeekErr;
  105.             
  106.             bytesInParagraph = (short) Getw (in);
  107.             CheckReadErr;    
  108.             
  109.             wwInit();
  110.             GNNeedToReadByte = 1;
  111.             parIsCompressed = paragraphStatus & COMPRESSED_MASK;
  112.             for (bytesOut=0; bytesOut<bytesInParagraph; bytesOut++)    {
  113.                 if (parIsCompressed) {            /*    a compressed paragraph */
  114.                     nibble = Getn (in);
  115.                     if (nibble == 0x0f) {        /*    means that next 2
  116.                                                     nibbles form the
  117.                                                     next char. */
  118.                         a = Getn (in);
  119.                         b = Getn (in);
  120.                         c = (a << 4) + b;
  121.                     }
  122.                     else c = CommonChars[nibble];
  123.                 } else                            /*    a regular paragraph */
  124.                     c = getc (in);
  125.                 
  126.                 if (c == EOF) {
  127.                     (void) fprintf(stderr, "%s: unexpected end of file.\n", name);
  128.                     return (4);
  129.                 }
  130.                 
  131.                 if (wwPutchar (c & 0x00ff))
  132.                     return (0);                    /* user skipped file */
  133.             }                                    /* end reading the para */
  134.             if (wwFlush())
  135.                 return (0);                        /* user skipped file */
  136.                 
  137.             Seek = fseek (in, saved, SEEK_SET);
  138.             CheckSeekErr;
  139.         }                                        /* end text paragraph */
  140.         else {
  141.                                                 /*    it's a ruler, but
  142.                                                     who cares? */
  143.         }
  144.         
  145.         if (++curpara >= numparas) break;
  146.     }                                            /* paragraph loop */
  147.  
  148.     return (0);                                    /* exit success, mon */
  149.  
  150. SeekErr:
  151.     (void) fprintf(stderr, "%s: seek error occurred.\n", name);
  152.     return (5);
  153.  
  154. ReadErr:
  155.     (void) fprintf(stderr, "%s: error occurred while trying to read the file.\n", name);
  156.     return (6);
  157. }    /* thrash_macwrite */
  158.  
  159.  
  160.  
  161.  
  162. int Getn (f)
  163.     FILE *f;
  164. {
  165.     static int c;
  166.     extern int GNNeedToReadByte;
  167.     
  168.     if (GNNeedToReadByte) {
  169.         c = getc(f);
  170.         if (c == EOF) return (EOF);
  171.         c &= 0x00ff;
  172.         GNNeedToReadByte = 0;    /* still got the other nibble to use. */
  173.         return (c >> 4);
  174.     }
  175.  
  176.     GNNeedToReadByte = 1;
  177.     return (c & 0x000f);    
  178. }    /* Getn */
  179.  
  180.  
  181.  
  182. /*    This huge mess only accomplishes one thing:  read in STR ID 700 from
  183.     the resource fork of this macwrite file.   What a waste... */
  184.     
  185. int FindCommon(in, dataForkLen)
  186.     FILE *in;
  187.     long dataForkLen;
  188. {
  189. #define COMMON_ID 700
  190.     register long        rezforkstart, typeliststart, Seek;
  191.     short                numtypes;
  192.     register short        foundSTR;
  193.     
  194.     struct Oy {
  195.         long            dataOffset, mapOffset, datalen, maplen;
  196.     } rheader;
  197.     
  198.     struct Foo {
  199.         long            crap[6];
  200.         short            typelistOffset, namelistOffset;
  201.     } rmapheader;
  202.     
  203.     struct Bar {
  204.         char            type[5];/* really only [4], but I'm not reading in
  205.                                     the whole structure at a time. */
  206.         short            n;        /* number of rsrcs - 1*/
  207.         short            offset;    /* from start of typelist to ref list */
  208.     } typeinfo;
  209.     
  210.     struct Grok {
  211.         short            id, nameoffset;
  212.         long            dataoffset;  /* from start of res data; lo 3 bytes */
  213.         long            handle;
  214.     } refinfo;
  215.  
  216.     rezforkstart = (((128L + dataForkLen) / 128) + 1) * 128;
  217.         /*    the resource fork starts after the header (128 bytes) and
  218.             after the data fork, which is padded to a multiple of 128. */
  219.             
  220.     Seek = fseek (in, rezforkstart, SEEK_SET);
  221.     if (Seek) goto done;        /* should be at rsrc fork start now */
  222.  
  223.     
  224.     /* read the resource file header. */
  225.     rheader.dataOffset = (long) Getl (in);
  226.     if (ferror (in)) goto done;
  227.     
  228.     rheader.mapOffset = (long) Getl (in);
  229.     if (ferror (in)) goto done;
  230.     
  231.     rheader.datalen = (long) Getl (in);
  232.     if (ferror (in)) goto done;
  233.     
  234.     rheader.maplen = (long) Getl (in);
  235.     if (ferror (in)) goto done;
  236.     
  237.     
  238.     /* read the resource MAP header. */
  239.     Seek = fseek (in, (long) (rezforkstart + rheader.mapOffset + 24L), SEEK_SET);
  240.     if (Seek) goto done;
  241.     
  242.     rmapheader.typelistOffset = (short) Getw (in); /* 6 craps * 4 bytes = 24L bytes. */
  243.     if (ferror (in)) goto done;
  244.     
  245.     
  246.     /* read the typelist. */
  247.     Seek = fseek (in, (long) (rezforkstart + rheader.mapOffset +
  248.         rmapheader.typelistOffset), SEEK_SET);
  249.     if (Seek) goto done;
  250.     
  251.     typeliststart = ftell (in);
  252.     
  253.     numtypes = (short) Getw (in) + 1;    /* rez manager stores (numtypes - 1) ! */
  254.     if (ferror(in)) goto done;
  255.     
  256.     foundSTR = 0;
  257.     while (!foundSTR && --numtypes >= 0) {
  258.         /* read in some info about the next type in the list. */
  259.         typeinfo.type[0] = (char) getc (in);
  260.         typeinfo.type[1] = (char) getc (in);
  261.         typeinfo.type[2] = (char) getc (in);
  262.         typeinfo.type[3] = (char) getc (in);
  263.         typeinfo.type[4] = '\0';
  264.         if (ferror (in)) goto done;
  265.         typeinfo.n = (short) Getw (in) + 1;    /* rez manager stores (numrsrcs - 1) ! */
  266.         if (ferror (in)) goto done;
  267.         typeinfo.offset = (short) Getw (in);
  268.         if (ferror (in)) goto done;
  269.         
  270.         foundSTR = (strcmp (STR_TYPE, typeinfo.type) == 0);
  271.     }
  272.     if (!foundSTR) goto done;    /* no 'STR '! */
  273.     Seek = fseek (in, (long) (typeliststart + typeinfo.offset), SEEK_SET);
  274.     if (Seek) goto done;
  275.         
  276.     while (--typeinfo.n >= 0) {
  277.         refinfo.id = (short) Getw (in);
  278.         if (ferror (in)) goto done;
  279.         refinfo.nameoffset = (short) Getw (in);
  280.         if (ferror (in)) goto done;
  281.         refinfo.dataoffset = (long) Getl (in);
  282.         if (ferror (in)) goto done;
  283.         refinfo.handle = (long) Getl (in);
  284.         if (ferror (in)) goto done;
  285.  
  286.         if (refinfo.id == COMMON_ID) break;
  287.     }
  288.     if (refinfo.id != COMMON_ID) goto done;        /* no CommonChars! */
  289.     
  290.     refinfo.dataoffset &= 0x00ffffff;    /* lo 3 bytes for offset */
  291.     Seek = fseek (
  292.         in, 
  293.         (long) (rezforkstart + refinfo.dataoffset +
  294.             rheader.dataOffset + 5L),    /*    4L for the length of the rsrc,
  295.                                             which we already know, and
  296.                                             another 1L for the pascal
  297.                                             string's length byte. */
  298.         SEEK_SET);
  299.     if (Seek) goto done;
  300.     
  301.     (void) fgets (CommonChars, 18, in);
  302.     CommonChars[16] = '\0';
  303.  
  304. done:
  305.     Seek = fseek (in, (long) 128, SEEK_SET);
  306. }
  307.  
  308. /* eof */
  309.